import { BubbleDt } from "../../../Framework/Common/CommonInterface";
import Emitter from "../../../Framework/Common/Emitter";
import DataMgr from "../../../Framework/Data/DataMgr";
import Bubble from "../Object/Bubble";
import Player from "../Object/Player";
import ModuleBase from "./ModuleBase";
import ModuleMgr from "./ModuleMgr";
import { PoolManager } from "./NodePool";
import PlayerLayer from "./PlayerLayer";
import PropLayer from "./PropLayer";
import TiledMapCtrl from "./TiledMapCtrl";

const { ccclass, property } = cc._decorator;
@ccclass
export default class BubbleLayer extends ModuleBase {
    //用于存储产生的泡泡
    private _arrBubble: Bubble[] = [];
    private _tiledMapCtrl: TiledMapCtrl = null;
    //存储需要贴水花的坐标,方向:[水花名:坐标]
    private _mapDir: Map<string, Map<string, cc.Vec2>[]> = new Map();
    private _propLayerTs: PropLayer = null;
    private _playerLayer: PlayerLayer = null;

    onInit(...rest: any[]): void {
        this._tiledMapCtrl = ModuleMgr.instance.getModule<TiledMapCtrl>("TiledMapCtrl");
        this._propLayerTs = ModuleMgr.instance.getModule<PropLayer>("PropLayer");
        this._playerLayer = ModuleMgr.instance.getModule<PlayerLayer>("PlayerLayer");
        //注册产生泡泡的消息
        Emitter.instance.on("AddBubble", this, this.createBubble);
        //注册泡泡爆炸的逻辑
        Emitter.instance.on("ToBomb", this, this.onBomb);
    }
    createBubble(playerPos: cc.Vec2, owner: Player) {
        console.log(owner.playerDt.bubbleNum);
        if (owner.playerDt.bubbleNum <= 0) {
            return;
        }
        let bubblePos = this._tiledMapCtrl.getCentralPos(playerPos);
        //计算释放泡泡的格子坐标
        let bubbleTilePos = this._tiledMapCtrl.getTiledPosByPoxiPos(bubblePos);
        //判断此坐标上是否有泡泡，如果有就不能在产生泡泡
        if (this.getBubbleByTiledPos(bubbleTilePos)) {
            return;
        }
        //如果泡泡出界，就不能产生泡泡
        if (this._tiledMapCtrl.isOutOfMap(bubbleTilePos)) {
            return;
        }
        let bubbleDt = DataMgr.instance.getMgr("bubbleDtMgr").getDataByID(5001 + owner.roleIndex) as BubbleDt;
        let bubbleName = bubbleDt.bubbleName;
        let bubbleNode = PoolManager.instance.getNodePool(bubbleName).getNode();
        bubbleNode.parent = this._tiledMapCtrl.node;
        //设置泡泡的坐标
        bubbleNode.setPosition(bubblePos);
        //设置泡泡的层级
        bubbleNode.setSiblingIndex(bubbleTilePos.y + 1);
        //将这个产生的泡泡脚本进行存储
        let bubbleTs = bubbleNode.getComponent(Bubble);
        this._arrBubble.push(bubbleTs);
        //将格子坐标进行存储
        bubbleTs.bubbleTiledPos = bubbleTilePos;
        bubbleTs.bubbleName = bubbleName;
        bubbleTs.onInit(owner, bubbleDt);
        owner.playerDt.bubbleNum--;
    }
    getBubbleByTiledPos(tiledPos: cc.Vec2) {
        for (let bubble of this._arrBubble) {
            if (bubble.bubbleTiledPos.equals(tiledPos)) {
                return bubble;
            }
        }
        return null;
    }
    onBomb(bubble: Bubble, tiledPos: cc.Vec2, power: number) {
        this._mapDir.clear();
        //收集所有格子坐标
        this.toBomb(bubble, tiledPos, power);
        //收集所有格子坐标后，将水花贴上
        Emitter.instance.emit("Blast", this._mapDir);
        //this.sendMsg("createBlast", "BlastLayer", this._mapDir);
    }
    //泡泡炸到泡泡时需要发生连锁反应，被炸到的泡泡也需要爆炸
    //可以在这个泡泡管理的位置，快速寻找到需要爆炸的泡泡
    //泡泡爆炸，需要去搜索泡泡能炸毁的障碍物，将其移除
    //这个函数执行泡泡爆炸的逻辑
    toBomb(bubble: Bubble, tiledPos: cc.Vec2, power: number) {
        //此爆炸的泡泡可能是被别的泡泡引爆的，这样放入对象池的泡泡再拿出来会继续计时，
        // 所以需要将所有泡泡的计时器停止
        bubble.unscheduleAllCallbacks();
        //移除泡泡
        this.removeBubble(bubble);
        //在地图上搜索可炸的格子上的障碍物，并且判断是否可以炸毁
        this.search(tiledPos, power, bubble);
    }
    //移除泡泡
    removeBubble(bubble: Bubble) {
        //将泡泡放回对象池中
        PoolManager.instance.getNodePool(bubble.bubbleName).putNode(bubble.node);
        //并且从存储泡泡的数组中将这个泡泡删除
        for (let i = 0; i < this._arrBubble.length; i++) {
            if (this._arrBubble[i] == bubble) {
                bubble.owner.playerDt.bubbleNum++;
                this._arrBubble.splice(i, 1);
                break;
            }
        }
    }

    //搜索格子
    search(tiledPos: cc.Vec2, power: number, blastingBubble: Bubble) {
        //获取爆炸的水花名
        let blastName = blastingBubble.blastName;
        //中心需要贴水花，中心的位置需要存储
        this.saveBlastTilePos("center", tiledPos, blastName);
        //判断中心是否有草丛，有的话可以将其炸毁
        let centerProperty = this._tiledMapCtrl.getPropertyByColliTiled(tiledPos);
        if (centerProperty && centerProperty.visible) {
            this._tiledMapCtrl.removeObstacle(tiledPos);
        }
        //有四个方向，先一个方向进行遍历，进行搜索，一个方向搜索婉，再搜索下一方向
        let objDir = {
            "up": cc.v2(0, -1),
            "down": cc.v2(0, 1),
            "left": cc.v2(-1, 0),
            "right": cc.v2(1, 0)
        }
        for (let strDir in objDir) {
            let startPos = tiledPos.clone();
            let dir: cc.Vec2 = objDir[strDir].clone();
            for (let i = 1; i <= power; i++) {
                let endPos = startPos.add(dir.clone().multiplyScalar(i));
                //如果位置出界了，就停止此方向向的搜索
                if (this._tiledMapCtrl.isOutOfMap(endPos)) {
                    break;
                }
                let property = this._tiledMapCtrl.getPropertyByColliTiled(endPos);
                if (property) {
                    if (property.blast) {
                        //如果这个障碍物是可炸的，就将其移除，并且此方向的搜索停止
                        //如果是草丛的话，炸毁草丛继续此方向上的搜索
                        this.saveBlastTilePos(strDir, endPos, blastName);
                        if (property.visible) {
                            this._tiledMapCtrl.removeObstacle(endPos);
                            //如果草丛下面有泡泡，也需要进行引爆
                            let bubble = this.getBubbleByTiledPos(endPos);
                            if (bubble) {
                                this.toBomb(bubble, endPos, bubble.power);
                            }
                            continue;
                        }
                        this._showProp(endPos);
                        this._tiledMapCtrl.removeObstacle(endPos);
                        break;
                    }
                    //如果遇到不可炸的障碍物，就停止这个方向上的搜索
                    break;
                }
                //没有障碍物，可以获取到道具
                let propTs = this._propLayerTs.getPropByTiledPos(endPos);
                if (propTs) {
                    this._propLayerTs.removeProp(endPos);
                }
                //如果没有障碍物，可能炸到
                let bubble = this.getBubbleByTiledPos(endPos);
                if (bubble) {
                    this.toBomb(bubble, endPos, bubble.power);
                    break;
                }
                let playerTs = this._playerLayer.getPlayerTsByTiledPos(endPos);
                if (playerTs && playerTs != blastingBubble.owner) {
                    playerTs.isDeath = true;
                    playerTs.statsCtrl.changeState("Die");
                }

                this.saveBlastTilePos(strDir, endPos, blastName);
            }
        }
    }
    //存储需要贴水花的坐标
    //存储需要贴水花的坐标,方向:[水花名:坐标]
    //private _mapDir: Map<string, Map<string, cc.Vec2>[]> = new Map();
    saveBlastTilePos(strDir: string, tiledPos: cc.Vec2, blastName: string) {
        let arrTile: Map<string, cc.Vec2>[] = this._mapDir.get(strDir);
        if (!arrTile) {
            arrTile = [];
            this._mapDir.set(strDir, arrTile);
        }
        let mapTile = new Map();
        mapTile.set(blastName, tiledPos);
        arrTile.push(mapTile);
    }

    private _showProp(tiledPos: cc.Vec2) {
        let prop = this._propLayerTs.getPropByTiledPos(tiledPos);
        if (prop && prop.node) {
            prop.node.active = true;
        }
    }
}
